﻿/*
 * LibLitePlayer.cpp
 *
 *  Created on: 2016年5月12日
 *      Author: terry
 */

#include "BasicType.h"
#include "LibLitePlayer.h"
#include "TMap.h"
#include "SharedPtr.h"
#include "LitePlayer.h"

typedef std::shared_ptr< av::LitePlayer >		LitePlayerPtr;


class PlayerHolder : public av::MediaEventSink, public av::MediaPacketSink, public av::MediaFrameSink
{
public:
	explicit PlayerHolder(void* hwnd):
		m_player(),
		m_callback(),
		m_context(),
        m_pktCallback(),
        m_pktContext(),
		m_frameCallback(),
		m_frameContext()
	{
		m_player.reset(av::LitePlayerFactory::create(hwnd), av::LitePlayerFactory::destroy);
		m_player->setEventSink(this);
        m_player->setFrameSink(this);
        m_player->setPacketSink(this);
	}

	~PlayerHolder()
	{
		m_player.reset();
	}



	LitePlayerPtr	m_player;
	PlayerEventCallback m_callback;
	void* m_context;
	comn::CriticalSection	m_cs;

    PlayerPacketCallback    m_pktCallback;
    void* m_pktContext;

    PlayerFrameCallback m_frameCallback;
    void* m_frameContext;

    av::MediaFormat m_format;

	void setEventCallback(PlayerEventCallback cb, void* context)
	{
		comn::AutoCritSec lock(m_cs);
		m_callback = cb;
		m_context = context;
	}

    void setPacketCallback(PlayerPacketCallback cb, void* context)
    {
        comn::AutoCritSec lock(m_cs);
        m_pktCallback = cb;
        m_pktContext = context;
    }

    void setFrameCallback(PlayerFrameCallback cb, void* context)
    {
        comn::AutoCritSec lock(m_cs);
        m_frameCallback = cb;
        m_frameContext = context;
    }

	virtual void onMediaEvent(av::LitePlayer* player, int type, int64_t value)
	{
		comn::AutoCritSec lock(m_cs);

		if (m_callback)
		{
			(*m_callback)(player, type, m_context);
		}
	}

    virtual void onMediaFormat(const av::MediaFormat& format)
    {
        m_format = format;
    }

    virtual void onMediaPacket(MediaPacket& packet)
    {
        if (m_pktCallback)
        {
            (*m_pktCallback)(m_player.get(), &packet, m_pktContext);
        }
    }

    virtual void onMediaEnd()
    {

    }

    virtual void onMediaFrameFormat(const av::MediaFormat& format)
    {
        //
    }

    virtual void onMediaFrame(MediaFrame& frame)
    {
        if (m_frameCallback)
        {
            (*m_frameCallback)(m_player.get(), &frame, m_frameContext);
        }

    }

    virtual void onMediaFrameEnd()
    {
        //
    }

};



typedef std::shared_ptr< PlayerHolder >		PlayerHolderPtr;

typedef comn::Map<PlayerHandle, PlayerHolderPtr >	PlayerMap;

static std::shared_ptr< PlayerMap > 	s_playerMap;


static void ensureInit()
{
	if (!s_playerMap)
	{
		player_startup();
	}
}

static PlayerHolderPtr getPlayerHolder(PlayerHandle handle)
{
	PlayerHolderPtr holder;
	if (s_playerMap)
	{
		s_playerMap->find(handle, holder);
	}
	return holder;
}


static PlayerHolderPtr removePlayerHolder(PlayerHandle handle)
{
	PlayerHolderPtr holder;
	if (s_playerMap)
	{
		s_playerMap->remove(handle, holder);
	}
	return holder;
}

static LitePlayerPtr getPlayer(PlayerHandle handle)
{
	PlayerHolderPtr holder = getPlayerHolder(handle);
	if (holder)
	{
		return holder->m_player;
	}
	return LitePlayerPtr();
}




/**
 * 初始化
 * 程序启动时调用, 仅调用一次
 */
DLLEXPORT void player_startup()
{
	if (s_playerMap)
	{
		return;
	}

	s_playerMap.reset(new PlayerMap());

	av::LitePlayerFactory::startup();
}

/**
 * 清理
 * 不再调用任何此库的API时, 执行清理
 */
DLLEXPORT void player_cleanup()
{
	if (s_playerMap)
	{
		s_playerMap.reset();
	}

	av::LitePlayerFactory::cleanup();
}

/**
 * 创建播放器
 * @param hwnd	窗口句柄
 * @return	播放器
 */
DLLEXPORT PlayerHandle player_create(void* hwnd)
{
	ensureInit();

	PlayerHolderPtr holder(new PlayerHolder(hwnd));
	PlayerHandle handle = holder->m_player.get();
	s_playerMap->put(handle, holder);

	return handle;
}

/**
 * 销毁播放器
 * @param player
 */
DLLEXPORT void player_destroy(PlayerHandle handle)
{
	if (!s_playerMap)
	{
		return;
	}

	PlayerHolderPtr holder = removePlayerHolder(handle);

}

/**
 * 打开媒体流
 * @param player
 * @param url		比如: rtsp://192.168.3.1
 * @return 0 表示成功, 其他表示错误码
 */
DLLEXPORT int player_open(PlayerHandle handle, const char* url)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return ENOENT;
	}

	int rc = player->open(url);

	return rc;
}

/**
 * 关闭播放器
 * @param player
 */
DLLEXPORT void player_close(PlayerHandle handle)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return ;
	}

	player->close();
}

/**
 * 判断播放器是否打开
 * @param player
 * @return > 0 表示打开
 */
DLLEXPORT int player_isOpen(PlayerHandle handle)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return -1;
	}
	return player->isOpen();
}

/**
 * 获取当前的媒体路径
 * @param player
 * @return 空表示没有打开
 */
DLLEXPORT const char* player_getUrl(PlayerHandle handle)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return "";
	}
	return player->getURL();
}

/**
 * 暂停播放
 * @param player
 * @return
 */
DLLEXPORT int player_pause(PlayerHandle handle)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return -1;
	}

	return player->pause();
}

/**
 * 停止播放
 * @param player
 * @return
 */
DLLEXPORT int player_stop(PlayerHandle handle)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return -1;
	}

	player->stop();
	return 0;
}

/**
 * 开始播放
 * @param player
 * @return
 */
DLLEXPORT int player_play(PlayerHandle handle)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return -1;
	}

	return player->play();
}

/**
 * 获取媒体格式
 * 在打开播放器,得到 PLAYER_EVENT_FORMAT_READY 事件通知后才有准确的媒体格式
 * @param player
 * @param fmt
 * @return 0 表示成功
 */
DLLEXPORT int player_getFormat(PlayerHandle handle, PlayerMediaFormat* fmt)
{
	if (!fmt)
	{
		return -1;
	}

	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return -1;
	}

	av::MediaFormat mediaFormat;
	if (!player->getFormat(mediaFormat))
	{
		return -1;
	}

	fmt->duration = mediaFormat.m_duration;
	fmt->codec = mediaFormat.m_codec;
	fmt->width = mediaFormat.m_width;
	fmt->height = mediaFormat.m_height;
	fmt->audioCodec = mediaFormat.m_audioCodec;
	fmt->channels = mediaFormat.m_channels;
	fmt->sampleRate= mediaFormat.m_sampleRate;

	return 0;
}

/**
 * 获取媒体播放状态
 * @param player
 * @return
 */
DLLEXPORT int player_getState(PlayerHandle handle)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return -1;
	}

	return player->getState();
}

/**
 * 获取音量, 取值范围为 [0, 1.0]
 * @param player
 * @return
 */
DLLEXPORT float player_getVolume(PlayerHandle handle)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return 0;
	}

	return player->getVolume();
}

/**
 * 设置音量
 * @param player
 * @param volume
 * @return
 */
DLLEXPORT int player_setVolume(PlayerHandle handle, float volume)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return -1;
	}

	return player->setVolume(volume);
}

/**
 * 获取静音
 * @param player
 * @return
 */
DLLEXPORT int player_isMute(PlayerHandle handle)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return -1;
	}

	return player->isMute();
}

/**
 * 设置静音
 * @param player
 * @return
 */
DLLEXPORT int player_setMute(PlayerHandle handle, int mute)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return -1;
	}

	return player->setMute(mute > 0);
}

/**
 * 是否全屏
 * @param player
 * @return
 */
DLLEXPORT int player_isFullscreen(PlayerHandle handle)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return -1;
	}

	return player->isFullscreen();
}

/**
 * 设置全屏
 * @param player
 * @param full
 * @return
 */
DLLEXPORT int player_setFullscreen(PlayerHandle handle, int full)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return -1;
	}

	return player->setFullscreen(full > 0);
}

/**
 * 设置显示比例
 * 如果cx,cy= 0, 保持视频的原始比率
 * @param player
 * @param cx	宽度比例
 * @param cy	高度比例
 * @return
 */
DLLEXPORT int player_setRatio(PlayerHandle handle, int cx, int cy)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return -1;
	}

	return player->setRatio(cx, cy);
}

/**
 * 获取显示比例
 * @param player	播放器
 * @param cx		宽度比例
 * @param cy		高度比例
 * @return
 */
DLLEXPORT int player_getRatio(PlayerHandle handle, int* cx, int* cy)
{
	if (!cx || !cy)
	{
		return -1;
	}

	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return -1;
	}

	player->getRatio(*cx, *cy);

	return 0;
}

/**
 * 设置视频显示窗口
 * @param hwnd	窗口句柄
 * @return
 */
DLLEXPORT int player_setVideoWnd(PlayerHandle handle, void* hwnd)
{
	LitePlayerPtr player = getPlayer(handle);
	if (!player)
	{
		return -1;
	}

	player->setVideoWnd(hwnd);

	return 0;
}


/**
 * 设置事件回调句柄
 * @param player	播放器
 * @param cb		回调函数
 * @param context	回调环境
 * @return
 */
DLLEXPORT int player_setEventCallback(PlayerHandle handle, PlayerEventCallback cb, void* context)
{
	PlayerHolderPtr holder = getPlayerHolder(handle);
	if (!holder)
	{
		return -1;
	}

	holder->setEventCallback(cb, context);

	return 0;
}


/**
 * 获取播放时长
 * @param handle
 * @return 播放时长, 单位为毫秒
 */
DLLEXPORT int player_getDuration(PlayerHandle handle)
{
    LitePlayerPtr player = getPlayer(handle);
    if (!player)
    {
        return 0;
    }

    return player->getDuration();
}

/**
 * 判断是否可定位
 * @param handle
 * @return > 0 表示可以拖拽定位
 */
DLLEXPORT int player_seekable(PlayerHandle handle)
{
    LitePlayerPtr player = getPlayer(handle);
    if (!player)
    {
        return -1;
    }

    return player->seekable();
}

/**
 * 定位到指定时间点
 * @param handle
 * @param offset  时间点，单位为毫秒，不应超过 duration
 * @return 0 表示成功
 */
DLLEXPORT int player_seek(PlayerHandle handle, int64_t offset)
{
    LitePlayerPtr player = getPlayer(handle);
    if (!player)
    {
        return -1;
    }

    return player->seek(offset);
}

/**
 * 获取当前已播放时长
 * @param handle
 * @return 播放时间，单位为毫秒
 */
DLLEXPORT int64_t player_getTime(PlayerHandle handle)
{
    LitePlayerPtr player = getPlayer(handle);
    if (!player)
    {
        return 0;
    }

    return player->getTime();
}

/**
 * 设置播放器logo
 * @param handle
 * @param filepath
 * @return
 */
DLLEXPORT int player_setImage(PlayerHandle handle, const char* filepath)
{
    LitePlayerPtr player = getPlayer(handle);
    if (!player)
    {
        return -1;
    }

    return player->setImage(filepath);
}

/**
 * 抓图
 * @param handle
 * @param filepath 图片路径
 * @return 0 表示成功
 */
DLLEXPORT int player_snap(PlayerHandle handle, const char* filepath)
{
    LitePlayerPtr player = getPlayer(handle);
    if (!player)
    {
        return -1;
    }

    return player->snap(filepath);
}


DLLEXPORT void player_setFrameSink(PlayerHandle handle, PlayerFrameCallback cb, void* context)
{
    PlayerHolderPtr holder = getPlayerHolder(handle);
    if (!holder)
    {
        return ;
    }

    holder->setFrameCallback(cb, context);
}

/**
 * 设置媒体流回调
 * @param pSink 接收未解码媒体包
 */
DLLEXPORT void player_setPacketSink(PlayerHandle handle, PlayerPacketCallback cb, void* context)
{
    PlayerHolderPtr holder = getPlayerHolder(handle);
    if (!holder)
    {
        return ;
    }

    holder->setPacketCallback(cb, context);
}

/**
 * 设置属性
 * @param handle
 * @param name 属性名称
 * @param value 属性值
 * @return true 表示成功
 */
DLLEXPORT int player_setProp(PlayerHandle handle, const char* name, const char* value)
{
    LitePlayerPtr player = getPlayer(handle);
    if (!player)
    {
        return -1;
    }

    return player->setProp(name, value);
}


/**
 * 开始录像
 * 不调用 stopRecord 而多次调用 startRecord , 可以实现无缝切换文件
 * @param handle
 * @param  filename  录像文件名称
 * @return 0 表示成功
 */
DLLEXPORT int player_startRecord(PlayerHandle handle, const char* filename)
{
    LitePlayerPtr player = getPlayer(handle);
    if (!player)
    {
        return -1;
    }

    return player->startRecord(filename);
}

/**
 * 停止录像
 * @param handle
 */
DLLEXPORT void player_stopRecord(PlayerHandle handle)
{
    LitePlayerPtr player = getPlayer(handle);
    if (!player)
    {
        return ;
    }

    player->stopRecord();
}

/**
 * @param handle
 *  是否在录像中
 */
DLLEXPORT  int player_isRecording(PlayerHandle handle)
{
    LitePlayerPtr player = getPlayer(handle);
    if (!player)
    {
        return -1;
    }

    return player->isRecording();
}

/**
 * 开始导出到TS文件
 * 不调用 stopExport 而多次调用 startExport , 可以实现无缝切换文件
 * @param  filename  录像文件名称
 * @return 0 表示成功
 */
DLLEXPORT int player_startExport(PlayerHandle handle, const char* filename)
{
    LitePlayerPtr player = getPlayer(handle);
    if (!player)
    {
        return -1;
    }

    return player->startExport(filename);
}

/**
 * 停止导出
 */
DLLEXPORT void player_stopExport(PlayerHandle handle)
{
    LitePlayerPtr player = getPlayer(handle);
    if (!player)
    {
        return ;
    }

    player->stopExport();
}

/// 是否在导出
DLLEXPORT int player_isExporting(PlayerHandle handle)
{
    LitePlayerPtr player = getPlayer(handle);
    if (!player)
    {
        return -1;
    }

    return player->isExporting();
}
